#ifndef SDKMANAGER_H
#define SDKMANAGER_H

#include <map>

#include "api/p2pms_client_interface.hpp"
#include "renderinterface.h"

using namespace p2pms;

struct MediaDev
{
    std::string id;
    std::string name;
};

//==================================================================================================
// 
//==================================================================================================
typedef std::function<void(bool)> LoginResultHandler;
typedef std::function<void(const std::string&)> UserAddHandler;
typedef std::function<void(const std::string&)> UserRemoveHandler;
typedef std::function<bool(const std::string&, const std::string&, const std::string&)>
	IncomingCallHandler;
typedef std::function<void(const std::string&, CallState)> CallStateChangedHandler;
typedef std::function<void(const std::string&, const MediaInfo&)> StartPublishNotifyHandler;
typedef std::function<void(const std::string&, const MediaInfo&)> StopPublishNotifyHandler;
typedef std::function<void(const std::string&, const MediaInfo&, bool)> StartSubscribeResultHandler;
typedef std::function<void(const std::string&, const MediaInfo&, bool)> StopSubscribeResultHandler;
typedef std::function<void(const MediaInfo&, bool)> StartPublishResultHandler;
typedef std::function<void(const MediaInfo&, bool)> StopPublishResultHandler;

//==================================================================================================
// 
//==================================================================================================
class SdkManager : public p2pms::IClientHandler
                 , public p2pms::IMainThreadExecutor
				 , public IRenderHandler
{
public:
    SdkManager();

    bool Init();
    bool Login(const std::string& user_id);
    std::string GetUserId() const { return m_user_id; }
    std::vector<MediaDev> GetAudioInputDevList();
    std::vector<MediaDev> GetVideoInputDevList();
    std::vector<MediaDev> GetAudioOutputDevList();
    std::vector<std::string> GetUserList();
    bool StartPublishVideo(const MediaDev& device, MediaInfo& media);
    bool StopPublishVideo(const MediaInfo& media);
    bool StartPublishAudio(const MediaDev& device, MediaInfo& media);
    bool StopPublishAudio(const MediaInfo& media);
    bool StartSubscribe(const std::string& user_id, const MediaInfo& media);
    bool StartRender(const MediaInfo& media);
    bool StopRender(const MediaInfo& media);
    void StopRenderAll();
    bool MakeCall(const std::string& mode, const std::string& callee);
    void TerminateCall();

	void RegisterLoginResultHandler(LoginResultHandler handler);
	void RegisterUserAddHandler(UserAddHandler handler);
	void RegisterUserRemoveHandler(UserRemoveHandler handler);
	void RegisterIncomingCallHandler(IncomingCallHandler handler);
    void RegisterCallStateChangedHandler(CallStateChangedHandler handler);
	void RegisterStartPublishNotifyHandler(StartPublishNotifyHandler handler);
	void RegisterStopPublishNotifyHandler(StopPublishNotifyHandler handler);
	void RegisterStartSubscribeResultHandler(StartSubscribeResultHandler handler);
	void RegisterStopSubscribeResultHandler(StopSubscribeResultHandler handler);
	void RegisterStartPublishResultHandler(StartPublishResultHandler handler);
	void RegisterStopPublishResultHandler(StopPublishResultHandler handler);

private:
    std::vector<MediaDev> GetDevList(p2pms::MediaDeviceType dev_type);

    // IRenderHandler
    void OnPaint(const std::string& render_id) override;
    void OnSizeChanged(const std::string& render_id) override;

    // IMainThreadExecutor
    void PostToMainThread(std::function<void()> func) override;

    // IClientHandler
    void OnLoginResult(bool result) override;
    void OnLoginNotify(const std::string& user_id) override;
    void OnLogoutNotify(const std::string& user_id) override;
    bool OnIncomingCall(const std::string& call_type, const std::string& user_id, 
		const std::string& call_id) override;
    void OnCallStateChanged(const std::string& call_id, CallState state) override;
    void OnStartPublish(const std::string& user_id, const MediaInfo& media) override;
    void OnStopPublish(const std::string& user_id, const MediaInfo& media) override;
    void OnStartPublishResult(const MediaInfo& media, bool result) override;
    void OnStopPublishResult(const MediaInfo& media, bool result) override;
    void OnStartSubscribeResult(const std::string& user_id, const MediaInfo& media, 
		bool result) override;
    void OnStopSubscribeResult(const std::string& user_id, const MediaInfo& media, 
		bool result) override;

private:
    p2pms::IP2PMSClient* m_client = nullptr;
    std::string m_user_id;

	// key: media_id, value: render_id
	// This map is used to track which media is being rendered and its associated render ID.
    std::map<std::string, std::string> m_media_renders;

	// Handlers for various events
	LoginResultHandler m_login_result_handler;
	UserAddHandler m_user_add_handler;
	UserRemoveHandler m_user_remove_handler;
	IncomingCallHandler m_incoming_call_handler;
    CallStateChangedHandler m_call_state_changed_handler;
	StartPublishNotifyHandler m_start_publish_notify_handler;
	StopPublishNotifyHandler m_stop_publish_notify_handler;
	StartSubscribeResultHandler m_start_subscribe_result_handler;
	StopSubscribeResultHandler m_stop_subscribe_result_handler;
	StartPublishResultHandler m_start_publish_result_handler;
	StopPublishResultHandler m_stop_publish_result_handler;
};

#endif // SDKMANAGER_H
